/**
 * Copyright (c) 2005-2023, Paul Tuckey
 * All rights reserved.
 * ====================================================================
 * Licensed under the BSD License. Text as follows.
 * <p>
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * <p>
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided
 * with the distribution.
 * - Neither the name tuckey.org nor the names of its contributors
 * may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 * <p>
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 */
package org.tuckey.web.filters.urlrewrite.functions;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * todo: turn into a css vars filter plugin
 * Quick and dirty limited implementation of css Variables in Java
 * <p/>
 * http://disruptive-innovations.com/zoo/cssvariables/
 * http://trac.webkit.org/browser/trunk/LayoutTests/fast/css/variables
 */
public class CssVarFunction {

    /*

 set variables, these bay be overriden by request attributes

@variables {
    gadgetBodyLinkColor: #c0c0c0;
}

h1 {
    border-color: var(gadgetBodyLinkColor);
}

     */


    static Pattern VARIABLE_SET_PATTERN = Pattern.compile("\\s*([a-zA-Z0-9-]+)\\s*\\:(.*);");
    static Pattern VARIABLE_REF_PATTERN = Pattern.compile("var\\(([a-zA-Z0-9-]+)\\)");
    static Pattern VARIABLES_BLOCK_START_PATTERN = Pattern.compile("@variables");

    public static void parse(InputStream cssFile, Map variables, OutputStream os) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(cssFile));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
        Map defaultVariables = new HashMap();

        if (variables == null) variables = new HashMap();
        String line;
        boolean readingVars = false;
        boolean emitNewLine = false;
        while ((line = br.readLine()) != null) {

            if (emitNewLine && !readingVars) bw.newLine();
            emitNewLine = true;

            if (!readingVars && VARIABLES_BLOCK_START_PATTERN.matcher(line).find()) readingVars = true;

            if (readingVars) {
                Matcher m = VARIABLE_SET_PATTERN.matcher(line);
                while (m.find()) {
                    defaultVariables.put(m.group(1), m.group(2));
                }
            }
            if (!readingVars) {
                Matcher m2 = VARIABLE_REF_PATTERN.matcher(line);
                StringBuffer sb = new StringBuffer();
                while (m2.find()) {
                    String var = m2.group(1);
                    String varValue = (String) variables.get(var);
                    if (varValue == null) varValue = (String) defaultVariables.get(var);
                    if (varValue == null) varValue = "";
                    m2.appendReplacement(sb, varValue);
                }
                m2.appendTail(sb);
                line = sb.toString();

                bw.write(line);
            }
            if (readingVars && line.matches("}")) {
                readingVars = false;
                emitNewLine = false;
            }
        }
        bw.flush();
    }

    public static String parse(String css, Map variables) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ByteArrayInputStream bais = new ByteArrayInputStream(css.getBytes());
        try {
            parse(bais, variables, baos);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return baos.toString();
    }

}

